﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Text;

    internal static class CodeGenUtilities
    {
        internal static bool AddImportIfNeeded(CodeNamespace codeNamespace, string importNamespace)
        {
            if (string.IsNullOrEmpty(importNamespace) || string.Equals(codeNamespace.Name, importNamespace, StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }
            foreach (CodeNamespaceImport import in codeNamespace.Imports)
            {
                if (string.Equals(import.Namespace, importNamespace, StringComparison.OrdinalIgnoreCase))
                {
                    return false;
                }
            }
            codeNamespace.Imports.Add(new CodeNamespaceImport(importNamespace));
            return true;
        }

        internal static CodeAttributeDeclaration CreateAttributeDeclaration(string attributeTypeName)
        {
            return new CodeAttributeDeclaration(new CodeTypeReference(attributeTypeName));
        }

        internal static CodeSnippetTypeMember CreateAutomaticPropertyDeclaration(CodeGenContext codeGenContext, CodeTypeDeclaration buddyClass, PropertyInfo propertyInfo, bool insideNamespace)
        {
            CodeMemberField member = new CodeMemberField(GetTypeReference(propertyInfo.PropertyType, codeGenContext, buddyClass), propertyInfo.Name) {
                Attributes = MemberAttributes.Public
            };
            CodeGeneratorOptions codeGeneratorOptions = codeGenContext.CodeGeneratorOptions;
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                string indentString = codeGeneratorOptions.IndentString;
                StringBuilder builder = new StringBuilder(indentString);
                builder.Append(indentString);
                if (insideNamespace)
                {
                    builder.Append(indentString);
                }
                codeGenContext.Provider.GenerateCodeFromMember(member, writer, codeGenContext.CodeGeneratorOptions);
                builder.Append(writer.GetStringBuilder());
                builder.Replace(Environment.NewLine, string.Empty);
                if (codeGenContext.IsCSharp)
                {
                    builder.Replace(";", " { get; set; }");
                }
                else
                {
                    int index = builder.ToString().IndexOf("Public", StringComparison.Ordinal) + "Public".Length;
                    builder.Insert(index, " Property");
                }
                return new CodeSnippetTypeMember(builder.ToString());
            }
        }

        internal static CodeTypeDeclaration CreateTypeDeclaration(string typeName, string ns)
        {
            CodeTypeDeclaration declaration = new CodeTypeDeclaration(typeName);
            declaration.UserData["Namespace"] = ns;
            return declaration;
        }

        internal static CodeCommentStatement GenerateXmlComment(string comment)
        {
            return new CodeCommentStatement(comment, true);
        }

        internal static CodeCommentStatementCollection GenerateXmlComments(string section, string body)
        {
            CodeCommentStatementCollection statements = new CodeCommentStatementCollection();
            statements.Add(new CodeCommentStatement("<" + section + ">", true));
            statements.Add(new CodeCommentStatement(body, true));
            statements.Add(new CodeCommentStatement("</" + section + ">", true));
            return statements;
        }

        internal static CodeTypeReference GetTypeReference(Type type)
        {
            return GetTypeReference(type, null, null);
        }

        internal static CodeTypeReference GetTypeReference(Type type, CodeGenContext codegenContext, CodeTypeDeclaration referencingType)
        {
            if ((type.IsPrimitive || (type == typeof(void))) || (((type == typeof(decimal)) || (type == typeof(string))) || (type == typeof(object))))
            {
                return new CodeTypeReference(type);
            }
            if ((codegenContext != null) && (referencingType != null))
            {
                CodeNamespace namespace2 = codegenContext.GetNamespace(referencingType);
                if ((namespace2 != null) && !namespace2.Name.Equals(type.Namespace))
                {
                    namespace2.Imports.Add(new CodeNamespaceImport(type.Namespace));
                }
            }
            if (type.IsArray)
            {
                return new CodeTypeReference(GetTypeReference(type.GetElementType(), codegenContext, referencingType), type.GetArrayRank());
            }
            if (!type.IsGenericType)
            {
                return new CodeTypeReference(type.Name);
            }
            Type[] genericArguments = type.GetGenericArguments();
            CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
            for (int i = 0; i < genericArguments.Length; i++)
            {
                typeArguments[i] = GetTypeReference(genericArguments[i]);
            }
            return new CodeTypeReference(type.Name, typeArguments);
        }

        public static bool IsValidGenericTypeParam(Type type)
        {
            if ((((type == null) || (!type.IsNested && !type.IsPublic)) || (type.IsNested && !type.IsNestedPublic)) || !type.IsClass)
            {
                return false;
            }
            if (type.GetConstructor(Type.EmptyTypes) == null)
            {
                return type.IsAbstract;
            }
            return true;
        }

        internal static CodeExpression MakeEqual(Type clrType, CodeExpression left, CodeExpression right, bool isCSharp)
        {
            if (isCSharp)
            {
                return new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.IdentityEquality, right);
            }
            if (((clrType != null) && clrType.IsGenericType) && (clrType.GetGenericTypeDefinition() == typeof(Nullable<>)))
            {
                return new CodeMethodInvokeExpression(left, "Equals", new CodeExpression[] { right });
            }
            if ((clrType != null) && clrType.IsValueType)
            {
                return new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.ValueEquality, right);
            }
            if (clrType == typeof(string))
            {
                return new CodeMethodInvokeExpression(null, "String.Equals", new CodeExpression[] { left, right });
            }
            return new CodeMethodInvokeExpression(null, typeof(object).Name + ".Equals", new CodeExpression[] { left, right });
        }

        internal static string MakeLegalEntityName(string entityName)
        {
            if (char.IsLower(entityName[0]))
            {
                entityName = char.ToUpperInvariant(entityName[0]) + entityName.Substring(1);
            }
            entityName = entityName.Replace('.', '_');
            return entityName;
        }

        internal static string MakeLegalParameterName(string entityName)
        {
            if (char.IsUpper(entityName[0]))
            {
                entityName = char.ToLowerInvariant(entityName[0]) + entityName.Substring(1);
            }
            entityName = entityName.Replace('.', '_');
            return entityName;
        }

        internal static CodeExpression MakeNotEqual(Type clrType, CodeExpression left, CodeExpression right, bool isCSharp)
        {
            if (isCSharp)
            {
                return new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.IdentityInequality, right);
            }
            return new CodeBinaryOperatorExpression(MakeEqual(clrType, left, right, isCSharp), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
        }

        internal static string StripAutoGenPrefix(string s, bool isCSharp)
        {
            string str = isCSharp ? "//" : "'";
            while (s.StartsWith(str, StringComparison.Ordinal))
            {
                int index = s.IndexOf("\r\n", StringComparison.Ordinal);
                s = s.Substring(index + 2);
            }
            return s;
        }
    }
}

